/*-
 * Copyright 2020 chenkang
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "iostream"
#include "bsdiff.h"
#include "lzzip.h"
#include "rom_api.h"
#include "file_handler.h"
#include <QFileDialog>
#include <QDir>
#include <QDataStream>
#include <QDebug>
#include <QFileInfo>
#include <QMessageBox>
#include <QFile>
#include <QPalette>
#include <QPixmap>
#include <QBrush>
#include <QDesktopServices>



BsDiff::BsDiff(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::BsDiff)
{
    ui->setupUi(this);
    ui->ROM_comboBox->addItem(tr("2kb"), QVariant(QString()));
    ui->ROM_comboBox->addItem(tr("3kb"), QVariant(QString()));
    ui->ROM_comboBox->addItem(tr("5kb"), QVariant(QString()));
    ui->ROM_comboBox->addItem(tr("9kb"), QVariant(QString()));
    ui->ROM_comboBox->addItem(tr("17kb"), QVariant(QString()));
    ui->ROM_comboBox->addItem(tr("33kb"), QVariant(QString()));
    connect(&thread, &MasterThread::response, this, &BsDiff::showResponse);
    connect(&thread, &MasterThread::error, this, &BsDiff::processError);
    connect(&thread, &MasterThread::Complete_Rate, this, &BsDiff::rate_changed);
    ui->diffbar->setValue(0);
}

BsDiff::~BsDiff()
{
    delete ui;
}


void BsDiff::rate_changed(const int &rate){
    ui->diffbar->setValue(rate);
}

void BsDiff::showResponse(const QString &s){
    ui->GenerateButton->setEnabled(true);
    ui->TestButton->setEnabled(true);
    ui->diffbar->setValue(100);
    QMessageBox msgBox;
    msgBox.setText(tr("Diff Complete\nPatch File is located:\n").append(s));
    QPushButton *OpenDirButton = msgBox.addButton(tr("open folder"), QMessageBox::ActionRole);
    QPushButton *OkButton = msgBox.addButton(tr("OK"), QMessageBox::ActionRole);
    msgBox.exec();
    QFileInfo opendir(s);

    if(msgBox.clickedButton() == OpenDirButton){
        QDesktopServices::openUrl(opendir.absolutePath());
    }
    else if(msgBox.clickedButton() == OkButton){

    }
    ui->diffbar->setValue(0);
}

void BsDiff::processError(const QString &s){
    ui->GenerateButton->setEnabled(true);
    QMessageBox::warning(this, tr("Error"), s, QMessageBox::Ok);
}

void BsDiff::on_GenerateButton_clicked()
{
    ui->GenerateButton->setEnabled(false);
    if(ui->NewFileCombox->currentText().isEmpty() || ui->OldFileCombox->currentText().isEmpty()){

        QMessageBox::warning(this, tr("warning"),
                                         tr("There is no OldFile or NewFile"),
                                         QMessageBox::Ok);
        ui->GenerateButton->setEnabled(true);
        return;
    }

    if(ui->Diff_comboBox->currentText().isEmpty()){
        ui->Diff_comboBox->addItem(QDir::currentPath());
        ui->Diff_comboBox->setCurrentText(QDir::currentPath());
    }
    thread.transaction(ui->OldFileCombox->currentText(), ui->NewFileCombox->currentText(),  \
                       ui->Diff_comboBox->currentText(), ui->ROM_comboBox->currentIndex());
}



void BsDiff::on_BrowserOldButton_clicked()
{
    QString OldFile = QFileDialog::getOpenFileName(this,
                               tr("Find Files"), QDir::currentPath());

    if (!OldFile.isEmpty()) {
        if (ui->OldFileCombox->findText(OldFile) == -1)
            ui->OldFileCombox->addItem(OldFile);
        ui->OldFileCombox->setCurrentIndex(ui->OldFileCombox->findText(OldFile));
        QFileInfo Oldfile_info(ui->OldFileCombox->currentText());
        QDir::setCurrent(Oldfile_info.absolutePath());
    }
}

void BsDiff::on_BrowserNewButton_clicked()
{
    QString NewFile = QFileDialog::getOpenFileName(this,
                               tr("Find Files"), QDir::currentPath());

    if (!NewFile.isEmpty()) {
        if (ui->NewFileCombox->findText(NewFile) == -1)
            ui->NewFileCombox->addItem(NewFile);
        ui->NewFileCombox->setCurrentIndex(ui->NewFileCombox->findText(NewFile));
        QFileInfo Newfile_info(ui->NewFileCombox->currentText());
        QDir::setCurrent(Newfile_info.absolutePath());
    }
}



void BsDiff::on_BrowserPathcButton_clicked()
{
    QString PatchFile = QFileDialog::getExistingDirectory(this, tr("Open Directory"),
                                                          QDir::currentPath(),
                                                          QFileDialog::ShowDirsOnly
                                                          | QFileDialog::DontResolveSymlinks);;

    if (!PatchFile.isEmpty()) {
        if (ui->Diff_comboBox->findText(PatchFile) == -1)
            ui->Diff_comboBox->addItem(PatchFile);
        ui->Diff_comboBox->setCurrentIndex(ui->Diff_comboBox->findText(PatchFile));
        QDir::setCurrent(PatchFile);
    }
}

void BsDiff::on_TestButton_clicked()
{
    FILE_INFORMATION file1;
    FILE_INFORMATION file2;
    FILE_INFORMATION file3;
    QStringList files;


    if(ui->Diff_comboBox->currentText().isEmpty()){
        QMessageBox::warning(this, tr("warning"),
                                         tr("There is no Patch_File"),
                                         QMessageBox::Ok);
    }

    QDir Patch_Dir(ui->Diff_comboBox->currentText());
    QFile oldfile(ui->OldFileCombox->currentText());
    QFileInfo Oldfile_info(ui->OldFileCombox->currentText());
    QString fileName(Oldfile_info.baseName().append(tr(".patch")));
    files = Patch_Dir.entryList(QStringList(fileName),
                                 QDir::Files | QDir::NoSymLinks);

    if(!files.isEmpty() && (files.count() == 1)){
        QFile Patch_File(ui->Diff_comboBox->currentText().append("/" + files[0]));
        QFileInfo Patchfile_info(ui->Diff_comboBox->currentText().append("/" + files[0]));
        QFile New_File(ui->Diff_comboBox->currentText().append("/" + Patchfile_info.baseName().append(tr(".new"))));

        if ((oldfile.open(QIODevice::ReadOnly)) && (Patch_File.open(QIODevice::ReadOnly)) \
                && (New_File.open(QIODevice::WriteOnly))){
            QDataStream Oldin(&oldfile);
            QDataStream Patchin(&Patch_File);
            QDataStream Newout(&New_File);

            int oldsize = oldfile.size();
            int Patchsize = Patch_File.size();
            int newsize;

            uint8_t *old_data = new uint8_t[oldsize + FLASH_PAGE_SIZE * 2];
            uint8_t *Patch_data = new uint8_t[Patchsize + FLASH_PAGE_SIZE * 2];

            Oldin.readRawData((char *)(((FLASH_ADDRESS)old_data + FLASH_PAGE_SIZE - 1) & (~(unsigned int)(FLASH_PAGE_SIZE - 1))), oldsize);
            Patchin.readRawData((char *)(((FLASH_ADDRESS)Patch_data + FLASH_PAGE_SIZE - 1) & (~(unsigned int)(FLASH_PAGE_SIZE - 1))), Patchsize);
            file1.file_address = (FLASH_ADDRESS)(old_data + FLASH_PAGE_SIZE - 1) & (~(FLASH_PAGE_SIZE - 1));
            file1.len = oldsize;
            file2.file_address = (FLASH_ADDRESS)(Patch_data + FLASH_PAGE_SIZE - 1) & (~(FLASH_PAGE_SIZE - 1));
            file2.len = Patchsize;



            FILE_ID *ffile1, *ffile2, *ffile3;
            ffile1 = file_open((FLASH_ADDRESS)&file1, FILEREAD_ONLY);
            ffile2 = file_open((FLASH_ADDRESS)&file2, FILEREAD_ONLY);
            file_lseek(ffile2, 4);
            if(file_read(ffile2, (uint8_t *)&newsize, 4) != 4){
                QMessageBox::warning(this, tr("warning"),
                                                 tr("read error"),
                                                 QMessageBox::Ok);
                delete []old_data;
                delete []Patch_data;
                return;
            }
            uint8_t *new_data = new uint8_t[newsize + FLASH_PAGE_SIZE * 2];
            file3.file_address = (FLASH_ADDRESS)(new_data + FLASH_PAGE_SIZE - 1) & (~(FLASH_PAGE_SIZE - 1));
            file3.len = 0;

            ffile3 = file_open((FLASH_ADDRESS)&file3, FILEWRITE_ONLY);

            BsPatch(ffile1, ffile2, ffile3);
            file_close(ffile1);
            file_close(ffile2);
            file_close(ffile3);
            newsize = file3.len;
            Newout.writeRawData((const char *)(((FLASH_ADDRESS)new_data + FLASH_PAGE_SIZE - 1) &     \
                                               (~(FLASH_ADDRESS)(FLASH_PAGE_SIZE - 1))), newsize);

            QMessageBox msgBox;
            msgBox.setText(tr("New File is located:\n"
                              "%1").arg(ui->Diff_comboBox->currentText().append("/"     \
                                + Patchfile_info.baseName().append(tr(".new")))));
            QPushButton *OpenDirButton = msgBox.addButton(tr("open folder"), QMessageBox::ActionRole);
            QPushButton *OkButton = msgBox.addButton(tr("OK"), QMessageBox::ActionRole);
            msgBox.exec();

            if(msgBox.clickedButton() == OpenDirButton){
                QDesktopServices::openUrl(ui->Diff_comboBox->currentText());
            }
            else if(msgBox.clickedButton() == OkButton){

            }
            delete []old_data;
            delete []Patch_data;
            delete []new_data;

        }

    }



}
